package ul.elab;


import java.{io};
import java.{util};
import java.{awt};
import javax.swing.{BoxLayout, KeyStroke, filechooser, DefaultComboBoxModel};
import javax.sound.{sampled};
import scala.{swing};
import ul.{audio};

import info.monitorenter.gui.chart.{Chart2D, ZoomableChart, ITrace2D, IAxis, traces, labelformatters, rangepolicies}
import info.monitorenter.util.{Range => AxisRange}


object GeneratorPanel extends swing.GridBagPanel {

    val tr: (String)=>String = Config.tran.tr _;
    
    var tabs: swing.TabbedPane = null;
    val generator = new audio.Generator { start() };
    val generators = List(
        new audio.SineGenerator(0.0,0.0,0.0),
        new audio.SawGenerator(0.0,0.0,0.0),
        new audio.InvSawGenerator(0.0,0.0,0.0),
        new audio.TriangleGenerator(0.0,0.0,0.0),
        new audio.SquareGenerator(0.0,0.0,0.0)
    );

    val waveformComboBox = new swing.ComboBox( List(
        tr("sine"),tr("sawtooth"),tr("inverted sawtooth"),tr("triangle"),tr("square")) ) {
        selection.index = Config("genWaveform").i;
    };

    val freqList = (for (f <- 1 to 9) yield (f * 10.0)).toList :::
        (for (f <- 1 to 9) yield (f * 100.0)).toList :::
        (for (f <- 1 to 20) yield (f * 1000.0)).toList;
    val freqComboBox = new swing.ComboBox( freqList ) {
        makeEditable(){ swing.ComboBox.doubleEditor };
        if (freqList.contains(Config("genFreq").d))
            selection.index = freqList.indexOf(Config("genFreq").d)
        else peer.getEditor.setItem( Config("genFreq").d );
    };

    val amplitudeList = (for (f <- 1 to 20) yield (f * 5.0)).toList;
    val amplitudeComboBox = new swing.ComboBox( amplitudeList ) {
        makeEditable(){ swing.ComboBox.doubleEditor };
        if (amplitudeList.contains(Config("genAmplitude").d))
            selection.index = amplitudeList.indexOf(Config("genAmplitude").d)
        else peer.getEditor.setItem( Config("genAmplitude").d );
    };

    val genStartButton = new swing.Button {
        action = swing.Action( tr("start") )();
        tooltip = tr("start generation")
    };
    val genStopButton = new swing.Button {
        action = swing.Action( tr("stop") )();
        tooltip = tr("stop generation");
        enabled = false;
    };

    val chartPanel: Chart2D = new Chart2D {
        getAxisX.setAxisTitle( new IAxis.AxisTitle( tr("time") )  );
        getAxisX.setPaintGrid( true );
        getAxisX.setPaintScale( true );
        getAxisY.setAxisTitle( new IAxis.AxisTitle( tr("amplitude") )  );
        getAxisY.setRange( new AxisRange( -32768.0, 32767 ) );
        getAxisY.setPaintGrid( true );
        getAxisY.setPaintScale( true );
        setUseAntialiasing( true );
        setToolTipType( Chart2D.ToolTipType.DATAVALUES );
        addTrace( new traces.Trace2DSimple( tr("wave period") ) {
            setColor( awt.Color.RED );
        });
    };
   
    def updateChart = {
        val trace = chartPanel.getTraces.first;
        trace.removeAllPoints;
        val generator = generators(Config("genWaveform").i);
        generator.setParams( Config("genFreq").d, Config("sourceFreq").i, 32768.0 * Config("genAmplitude").d / 100.0, 0.0 );
        val genFreq = Config("genFreq").d;
        for (a <- 0 to ((2 * math.Pi / generator.angleStep).toInt - 1)) {
            val time = generator.angle / ( 2.0 * math.Pi * genFreq );
            trace.addPoint( time, generator.nextSample );
        }
        chartPanel.setRequestedRepaint(true);
    };
    updateChart;
   
    add(
        new swing.Label( tr(" waveform : ") ),
        new this.Constraints( 0,0, 1,1, 0.1,1.0,
            swing.GridBagPanel.Anchor.Center.id,
            swing.GridBagPanel.Fill.None.id,
            new awt.Insets(0,0,0,0),
            0,0
        )
    );
    add(
        waveformComboBox,
        new this.Constraints( 1,0, 1,1, 1.0,1.0,
            swing.GridBagPanel.Anchor.Center.id,
            swing.GridBagPanel.Fill.Horizontal.id,
            new awt.Insets(0,0,0,0),
            0,0
        )
    );

    add(
        new swing.Label( tr(" frequency,Hz : ") ),
        new this.Constraints( 2,0, 1,1, 0.1,1.0,
            swing.GridBagPanel.Anchor.Center.id,
            swing.GridBagPanel.Fill.None.id,
            new awt.Insets(0,0,0,0),
            0,0
        )
    );
    add(
        freqComboBox,
        new this.Constraints( 3,0, 1,1, 1.0,1.0,
            swing.GridBagPanel.Anchor.Center.id,
            swing.GridBagPanel.Fill.Horizontal.id,
            new awt.Insets(0,0,0,0),
            0,0
        )
    );

    add(
        new swing.Label( tr(" amplitude,% : ") ),
        new this.Constraints( 4,0, 1,1, 0.1,1.0,
            swing.GridBagPanel.Anchor.Center.id,
            swing.GridBagPanel.Fill.None.id,
            new awt.Insets(0,0,0,0),
            0,0
        )
    );
    add(
        amplitudeComboBox,
        new this.Constraints( 5,0, 1,1, 1.0,1.0,
            swing.GridBagPanel.Anchor.Center.id,
            swing.GridBagPanel.Fill.Horizontal.id,
            new awt.Insets(0,0,0,0),
            0,0
        )
    );

    add(
        genStartButton,
        new this.Constraints( 0,1, 3,1, 1.0,1.0,
            swing.GridBagPanel.Anchor.Center.id,
            swing.GridBagPanel.Fill.Horizontal.id,
            new awt.Insets(0,0,0,0),
            0,0
        )
    );
    add(
        genStopButton,
        new this.Constraints( 3,1, 3,1, 1.0,1.0,
            swing.GridBagPanel.Anchor.Center.id,
            swing.GridBagPanel.Fill.Horizontal.id,
            new awt.Insets(0,0,0,0),
            0,0
        )
    );

    peer.add( chartPanel,
        new awt.GridBagConstraints( 0,2, 6,1, 1.0,100.0,
            swing.GridBagPanel.Anchor.Center.id,
            swing.GridBagPanel.Fill.Both.id,
            new awt.Insets(0,0,0,0),
            0,0
        )
    );



    listenTo(
        waveformComboBox.selection, freqComboBox.selection, amplitudeComboBox.selection,
        genStartButton, genStopButton
    );
    reactions += {
        case swing.event.SelectionChanged(`waveformComboBox`) =>
            Config("genWaveform").i = waveformComboBox.selection.index;
            updateChart;
        case swing.event.SelectionChanged(`freqComboBox`) =>
            if (freqComboBox.selection.item < 5.0) freqComboBox.selection.item = 5.0
            else if (freqComboBox.selection.item > 100000.0) freqComboBox.selection.item = 100000.0
            else Config("genFreq").d = freqComboBox.selection.item;
            updateChart;
        case swing.event.SelectionChanged(`amplitudeComboBox`) =>
            if (amplitudeComboBox.selection.item < 1.0) amplitudeComboBox.selection.item = 1.0
            else if (amplitudeComboBox.selection.item > 100.0) amplitudeComboBox.selection.item = 100.0
            else Config("genAmplitude").d = amplitudeComboBox.selection.item;
            updateChart;
        case swing.event.ButtonClicked(`genStartButton`) =>
            //println("Start");
            val mixer = audio.Audio.mixer( Config("sourceMixer").s );
            if (!mixer.isEmpty) {
                val line = audio.Audio.sourceDataLine( mixer.get, Config("sourceLine").s );
                if (!line.isEmpty) {
                    try {
                        line.get.open( new sampled.AudioFormat(
                            Config("sourceFreq").f, // sample frequency
                            16, // sample bits
                            1, // channels
                            true, // signed
                            false // little-endian
                        ));
                        val waveGen = generators(Config("genWaveform").i);
                        waveGen.setParams(Config("genFreq").d, Config("sourceFreq").d, Config("genAmplitude").d * 32767.0 / 100.0, 0.0);
                        generator ! audio.SetMixer(mixer.get);
                        generator ! audio.SetSourceLine(line.get);
                        generator ! audio.SetGenerator(waveGen);
                        generator ! audio.StartGeneration;
                        
                        waveformComboBox.enabled = false;
                        freqComboBox.enabled = false;
                        amplitudeComboBox.enabled = false;
                        genStartButton.enabled = false;
                        genStopButton.enabled = true;
                        tabs.enabled = false;
                        
                    } catch {
                        case _ =>
                    }
                }
            }
        case swing.event.ButtonClicked(`genStopButton`) =>
            //println("Stop")
            generator ! audio.StopGeneration;
            waveformComboBox.enabled = true;
            freqComboBox.enabled = true;
            amplitudeComboBox.enabled = true;
            genStartButton.enabled = true;
            genStopButton.enabled = false;
            tabs.enabled = true;
    };

}

